#include"LFMCrypter.h" 

#include<assert.h>

#include<QDir>
#include<QFile>

#include"LFMPostDataBuilder.h" //To use its api_key for encryption, I guess :/

LFMCrypter::LFMCrypter(){
#ifdef ENABLE_KEYCZAR
	m_crypter = 0;
	if(!QDir("crypter_key").exists()){
		QDir(".").mkdir("crypter_key");
	}else
		m_crypter = keyczar::Crypter::Read("crypter_key");
	
	if(!m_crypter){
		if(system("keyczart create --location=crypter_key --purpose=crypt && keyczart addkey --location=crypter_key --status=primary")==0)
			m_crypter = keyczar::Crypter::Read("crypter_key");
	}
	
	assert(m_crypter);
#endif
#ifndef ENABLE_KEYCZAR
	m_key = new QCA::SymmetricKey(LFMPostDataBuilder::api_key().left(16).toUtf8());
	m_iv = new QCA::InitializationVector(LFMPostDataBuilder::api_key().right(16).toUtf8());
	m_cipher = new QCA::Cipher("aes128", QCA::Cipher::CBC, QCA::Cipher::DefaultPadding, QCA::Encode, *m_key, *m_iv);
#endif
}

LFMCrypter::~LFMCrypter(){
#ifdef ENABLE_KEYCZAR
	delete m_crypter;
	m_crypter = 0;
#endif
}

QString LFMCrypter::encrypt(const QString &data){
#ifdef ENABLE_KEYCZAR
	std::string ret;
	m_crypter->Encrypt(data.toStdString(), &ret);
	return QString(ret.c_str());
#endif
#ifndef ENABLE_KEYCZAR
	QCA::SecureArray plain = data.toUtf8();
	m_cipher->setup(QCA::Encode, *m_key, *m_iv);
	QCA::SecureArray ret = m_cipher->update(plain);
	ret = ret.append( m_cipher->final() );
	return QCA::arrayToHex(ret.data());
	
	/*
	QCA::SecureArray plain = data.toUtf8().data();
	QCA::SymmetricKey key(LFMPostDataBuilder::api_key().left(16).toUtf8());
	QCA::InitializationVector iv(LFMPostDataBuilder::api_key().right(16).toUtf8());
	QCA::Cipher cipher("aes128", QCA::Cipher::CBC, QCA::Cipher::DefaultPadding, QCA::Encode, key, iv);
	
	QCA::SecureArray ret = cipher.update(plain);
	if(!cipher.ok()){
		printf("Encryption error :/\n");
		return data;
	}
	
	QCA::SecureArray f = cipher.final();
	if(!cipher.ok()){
		printf("Final failed.\n");
		return data;
	}
	
	printf("AES128 encryption of %s is [%s]\n",
               plain.data(),
               qPrintable(QCA::arrayToHex(ret.toByteArray())) );
	
	cipher.setup(QCA::Decode, key, iv);
	
	ret = ret.append(f);
	return ret.data();
	
	QCA::SecureArray plainText = cipher.update(ret);
	
	if(!cipher.ok()){
		printf("Update failed.\n");
		return data;
	}
	
	// output results
        printf("Decryption using AES128 of [0x%s] is %s\n",
               qPrintable(QCA::arrayToHex(ret.toByteArray())), plainText.data());
	
	plainText = cipher.final();

        // check if the final() call worked
        if (!cipher.ok()) {
		printf("Final2 failed\n");
        }
        
        printf("Final decryption block using AES128 is %s\n", plainText.data());
	
	return plainText.data();*/
#endif
}

QString LFMCrypter::decrypt(const QString &data){
#ifdef ENABLE_KEYCZAR
	std::string ret;
	m_crypter->Decrypt(data.toStdString(), &ret);
	return QString(ret.c_str());
#endif
#ifndef ENABLE_KEYCZAR
	QCA::SecureArray cipherText = QCA::hexToArray(data.toUtf8());
	m_cipher->setup(QCA::Decode, *m_key, *m_iv);
	QCA::SecureArray ret = m_cipher->update(cipherText);
	ret.append(m_cipher->final());
	return ret.data();
#endif
}

void LFMCrypter::encryptToFile(const QString &data, const QString &filename){
	QString temp = encrypt(data);
		
	QFile file(filename);
	if(file.open(QIODevice::WriteOnly)){
		file.write(temp.toUtf8().data());
		file.close();
	}else
		printf("Error opening file: %s\n", filename.toUtf8().data());
}

QString LFMCrypter::decryptFromFile(const QString &filename){
	QFile file(filename);
	if(!file.open(QIODevice::ReadOnly)){
		printf("Couldn't open session.\n");
		return QString();
	}
	
	QString temp = file.readAll();
	file.close();
	
	return decrypt(temp);
}
